/*
 Xern Entity Relocation Network
 Copyright (C) 2011 Ronie Salgado <roniesalg@gmail.com>

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

#include "Message.hpp"

namespace XernMetaverse
{
    // MessageVariable implementation.
    MessageVariable::MessageVariable(int id, const MessageBlock *p)
    {
        this->buffer = NULL;
        this->bufferSize = 0;
        this->variableId = id;
        this->parent = p;

        const MessageVariableTemplate &tmpl = GetTemplate();
        if(tmpl.type == MessageVariableTemplate::VT_FIXED)
        {
            this->bufferSize = tmpl.size;
            this->buffer = new unsigned char [this->bufferSize];
        }
    }

    MessageVariable::~MessageVariable()
    {
        if(this->buffer)
            delete [] this->buffer;
    }

    const MessageVariableTemplate &MessageVariable::GetTemplate() const
    {
        assert(parent);
        return parent->GetTemplate()->variables[variableId];
    }

    const MessageBlock &MessageVariable::GetParent() const
    {
        return *parent;
    }

    size_t MessageVariable::GetSize() const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        if(tmpl.HasVariableSize())
            return this->bufferSize + tmpl.size; // Add the size of the amount field.
        return tmpl.GetFixedSize();
    }

    void MessageVariable::Write(DataStream &out)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();

        // Do something different for each variable type.
        switch(tmpl.type)
        {
        case MessageVariableTemplate::VT_NULL:
            // Do nothing;
            break;
        case MessageVariableTemplate::VT_FIXED:
            {
                // Write every byte of the buffer.
                for(int i = 0; i < this->bufferSize; i++)
                    out.WriteLittle<u8> (this->buffer[i]);
            }
            break;
        case MessageVariableTemplate::VT_VARIABLE:
            {
                // Write the number of elements.
                if(tmpl.size == 1)
                    out.WriteLittle<u8> ((int)this->bufferSize);
                else if(tmpl.size == 2)
                    out.WriteLittle<u16> ((int)this->bufferSize);
                else
                    assert(NULL);

                // Write every byte of the buffer.
                for(int i = 0; i < this->bufferSize; i++)
                    out.WriteLittle<u8> (this->buffer[i]);
            }
            break;
        case MessageVariableTemplate::VT_U8:
            out.WriteLittle<u8> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_U16:
            out.WriteLittle<u16> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_U32:
            out.WriteLittle<u32> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_U64:
            out.WriteLittle<u64> (this->ulvalue);
            break;
        case MessageVariableTemplate::VT_S8:
            out.WriteLittle<s8> (this->svalue);
            break;
        case MessageVariableTemplate::VT_S16:
            out.WriteLittle<s16> (this->svalue);
            break;
        case MessageVariableTemplate::VT_S32:
            out.WriteLittle<s32> (this->svalue);
            break;
        case MessageVariableTemplate::VT_S64:
            out.WriteLittle<s64> (this->slvalue);
            break;
        case MessageVariableTemplate::VT_F32:
            out.WriteLittle<f32> (this->fvalue[0]);
            break;
        case MessageVariableTemplate::VT_F64:
            out.WriteLittle<f64> (this->dvalue[0]);
            break;
        case MessageVariableTemplate::VT_LLVECTOR3:
            out.WriteLittle<f32> (this->fvalue[0]);
            out.WriteLittle<f32> (this->fvalue[1]);
            out.WriteLittle<f32> (this->fvalue[2]);
            break;
        case MessageVariableTemplate::VT_LLVECTOR3D:
            out.WriteLittle<f64> (this->dvalue[0]);
            out.WriteLittle<f64> (this->dvalue[1]);
            out.WriteLittle<f64> (this->dvalue[2]);
            break;
        case MessageVariableTemplate::VT_LLQUATERNION:
            out.WriteLittle<f32> (this->fvalue[0]);
            out.WriteLittle<f32> (this->fvalue[1]);
            out.WriteLittle<f32> (this->fvalue[2]);
        	break;
        case MessageVariableTemplate::VT_LLVECTOR4:
            out.WriteLittle<f32> (this->fvalue[0]);
            out.WriteLittle<f32> (this->fvalue[1]);
            out.WriteLittle<f32> (this->fvalue[2]);
            out.WriteLittle<f32> (this->fvalue[3]);
            break;
        case MessageVariableTemplate::VT_LLUUID:
			{
				for(int i = 0; i < 16; i++)
					out.WriteLittle<u8> (guidValue.data[i]);
			}
            break;
        case MessageVariableTemplate::VT_BOOL:
            out.WriteBig<u8> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_IPADDR:
            out.WriteBig<u32> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_IPPORT:
            out.WriteBig<u16> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_U16VEC3:
        case MessageVariableTemplate::VT_U16QUAT:
        case MessageVariableTemplate::VT_S16ARRAY:
            assert(NULL); // Unsupported.
            break;
        }
    }

    void MessageVariable::Read(DataStream &in)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();

        // Do something different for each type.
        switch(tmpl.type)
        {
        case MessageVariableTemplate::VT_NULL:
            // Do nothing;
            break;
        case MessageVariableTemplate::VT_FIXED:
        {
            // Read all of the buffer data.
            for(int i = 0; i < this->bufferSize; i++)
                in.ReadLittle<u8> (this->buffer[i]);
        }
            break;
        case MessageVariableTemplate::VT_VARIABLE:
        {
            // Read the buffer size.
            unsigned int temp;
            if(tmpl.size == 1)
                in.ReadLittleTo<u8> (temp);
            else if(tmpl.size == 2)
                in.ReadLittleTo<u16> (temp);
            else
                assert(NULL);
            this->bufferSize = temp;

            // Delete the old buffer, if present.
            if(this->buffer)
                delete [] this->buffer;

            // Create a new buffer to contain the data.
            this->buffer = new unsigned char[this->bufferSize];

            // Read all of the buffer data.
            for(int i = 0; i < this->bufferSize; i++)
            	in.ReadLittle<u8> (this->buffer[i]);
        }
            break;
        case MessageVariableTemplate::VT_U8:
            in.ReadLittleTo<u8> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_U16:
            in.ReadLittleTo<u16> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_U32:
            in.ReadLittleTo<u32> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_U64:
            in.ReadLittleTo<u64> (this->ulvalue);
            break;
        case MessageVariableTemplate::VT_S8:
            in.ReadLittleTo<s8> (this->svalue);
            break;
        case MessageVariableTemplate::VT_S16:
            in.ReadLittleTo<s16> (this->svalue);
            break;
        case MessageVariableTemplate::VT_S32:
            in.ReadLittleTo<s32> (this->svalue);
            break;
        case MessageVariableTemplate::VT_S64:
            in.ReadLittleTo<s64> (this->slvalue);
            break;
        case MessageVariableTemplate::VT_F32:
            in.ReadLittleTo<f32> (this->fvalue[0]);
            break;
        case MessageVariableTemplate::VT_F64:
            in.ReadLittleTo<f64> (this->dvalue[0]);
            break;
        case MessageVariableTemplate::VT_LLVECTOR3:
            in.ReadLittleTo<f32> (this->fvalue[0]);
            in.ReadLittleTo<f32> (this->fvalue[1]);
            in.ReadLittleTo<f32> (this->fvalue[2]);
            break;
        case MessageVariableTemplate::VT_LLVECTOR3D:
            in.ReadLittleTo<f64> (this->dvalue[0]);
            in.ReadLittleTo<f64> (this->dvalue[1]);
            in.ReadLittleTo<f64> (this->dvalue[2]);
            break;
        case MessageVariableTemplate::VT_LLQUATERNION:
        	in.ReadLittleTo<f32> (this->fvalue[0]);
        	in.ReadLittleTo<f32> (this->fvalue[1]);
        	in.ReadLittleTo<f32> (this->fvalue[2]);
        	break;
        case MessageVariableTemplate::VT_LLVECTOR4:
            in.ReadLittleTo<f32> (this->fvalue[0]);
            in.ReadLittleTo<f32> (this->fvalue[1]);
            in.ReadLittleTo<f32> (this->fvalue[2]);
            in.ReadLittleTo<f32> (this->fvalue[3]);
            break;
        case MessageVariableTemplate::VT_LLUUID:
			{
				for(int i = 0; i < 16; i++)
					in.ReadLittle<u8> (guidValue.data[i]);
			}
            break;
        case MessageVariableTemplate::VT_BOOL:
            in.ReadBigTo<u8> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_IPADDR:
            in.ReadBigTo<u32> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_IPPORT:
            in.ReadBigTo<u16> (this->uvalue);
            break;
        case MessageVariableTemplate::VT_U16VEC3:
        case MessageVariableTemplate::VT_U16QUAT:
        case MessageVariableTemplate::VT_S16ARRAY:
            assert(NULL); // Unsupported.
            break;
        }
    }

    // Variable value manipulation functions.
    void MessageVariable::SetUIntValue(unsigned int value)
    {
        // Check the type validity.
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(
            tmpl.type == MessageVariableTemplate::VT_U8 ||
            tmpl.type == MessageVariableTemplate::VT_U16 ||
            tmpl.type == MessageVariableTemplate::VT_U32 ||
            tmpl.type == MessageVariableTemplate::VT_BOOL
        );

        // Perform the variable assignment.
        this->uvalue = value;
    }

    void MessageVariable::SetSIntValue(signed int value)
    {
        // Check the type validity.
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(
            tmpl.type == MessageVariableTemplate::VT_S8 ||
            tmpl.type == MessageVariableTemplate::VT_S16 ||
            tmpl.type == MessageVariableTemplate::VT_S32
        );

        // Perform the variable assignment.
        this->svalue = value;
    }

    void MessageVariable::SetUInt64Value(uint64_t value)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_U64);
        this->ulvalue = value;
    }

    void MessageVariable::SetSInt64Value(int64_t value)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_S64);
        this->slvalue = value;
    }

    void MessageVariable::SetGuidValue(const uuid &value)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_LLUUID);
        this->guidValue = value;
    }

    void MessageVariable::SetFloatValue(float value)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_F32);
        this->fvalue[0] = value;
    }

    void MessageVariable::SetDoubleValue(double value)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_F64);
        this->dvalue[0] = value;
    }

    void MessageVariable::SetVectorValue(float x, float y, float z)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_LLVECTOR3 ||
                tmpl.type == MessageVariableTemplate::VT_LLQUATERNION);
        this->fvalue[0] = x;
        this->fvalue[1] = y;
        this->fvalue[2] = z;
    }

    void MessageVariable::SetVectorValue(double x, double y, double z)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_LLVECTOR3D);
        this->dvalue[0] = x;
        this->dvalue[1] = y;
        this->dvalue[2] = z;
    }

    void MessageVariable::SetVectorValue(float x, float y, float z, float w)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_LLVECTOR4);
        this->fvalue[0] = x;
        this->fvalue[1] = y;
        this->fvalue[2] = z;
        this->fvalue[3] = w;
    }

    // Variable value retrieving.
    unsigned int MessageVariable::GetUIntValue() const
    {
        // Check the type validity.
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(
            tmpl.type == MessageVariableTemplate::VT_U8 ||
            tmpl.type == MessageVariableTemplate::VT_U16 ||
            tmpl.type == MessageVariableTemplate::VT_U32 ||
            tmpl.type == MessageVariableTemplate::VT_BOOL
        );

        return this->uvalue;
    }

    signed int MessageVariable::GetSIntValue() const
    {
        // Check the type validity.
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(
            tmpl.type == MessageVariableTemplate::VT_S8 ||
            tmpl.type == MessageVariableTemplate::VT_S16 ||
            tmpl.type == MessageVariableTemplate::VT_S32
        );

        return this->svalue;
    }

    uint64_t MessageVariable::GetUInt64Value() const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_U64);
        return this->ulvalue;
    }

    int64_t MessageVariable::GetSInt64Value() const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_S64);
        return this->slvalue;
    }

    float MessageVariable::GetFloatValue() const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_F32);
        return this->fvalue[0];
    }

    double MessageVariable::GetDoubleValue() const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_F64);
        return this->dvalue[0];
    }

    uuid MessageVariable::GetGuidValue() const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_LLUUID);
        return this->guidValue;
    }

    void MessageVariable::GetVectorValue(float &x, float &y, float &z) const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_LLVECTOR3 ||
                tmpl.type == MessageVariableTemplate::VT_LLQUATERNION);
        x = this->fvalue[0];
        y = this->fvalue[1];
        z = this->fvalue[2];
    }

    void MessageVariable::GetVectorValue(double &x, double &y, double &z) const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_LLVECTOR3D);
        x = this->dvalue[0];
        y = this->dvalue[1];
        z = this->dvalue[2];
    }

    void MessageVariable::GetVectorValue(float &x, float &y, float &z, float &w) const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_LLVECTOR4);
        x = this->fvalue[0];
        y = this->fvalue[1];
        z = this->fvalue[2];
        w = this->fvalue[3];
    }

    void *MessageVariable::GetBuffer()
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_FIXED ||
               tmpl.type == MessageVariableTemplate::VT_VARIABLE);
        return this->buffer;
    }

    const void *MessageVariable::GetBuffer() const
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_FIXED ||
               tmpl.type == MessageVariableTemplate::VT_VARIABLE);
        return this->buffer;
    }

    size_t MessageVariable::GetBufferSize() const
    {
        return this->bufferSize;
    }

    void MessageVariable::SetBufferSize(size_t size)
    {
        const MessageVariableTemplate &tmpl = GetTemplate();
        assert(tmpl.type == MessageVariableTemplate::VT_VARIABLE);

        this->bufferSize = size;
        if(this->buffer)
            delete [] this-> buffer;

        this->buffer = new unsigned char[size];
    }

    // MessageBlock implementation.
    MessageBlock::MessageBlock(int id, const Message *p)
    {
        subcount = 0;
        blockId = id;
        parent = p;

        boost::shared_ptr<const MessageBlockTemplate> tmpl = GetTemplate();
        subcount = tmpl->numrepetitions;
        variables.reserve(tmpl->variables.size()*subcount);
        int numvariables = tmpl->variables.size();
        //printf("PrepareBlock(%p, %p)\n", p, this);
        for(int i = 0; i < tmpl->numrepetitions; i++)
        {
            for(int j = 0; j < tmpl->variables.size(); j++)
                variables.push_back(boost::shared_ptr<MessageVariable> (new MessageVariable(j, this)));
        }
    }

    MessageBlock::~MessageBlock()
    {
    }

    size_t MessageBlock::GetSize() const
    {
        // Check the template for a fixed size.
        boost::shared_ptr<const MessageBlockTemplate> tmpl = GetTemplate();
        if(!tmpl->HasVariableSize())
        {
            return tmpl->GetBlockSize() * tmpl->numrepetitions;
        }

        // Number of blocks.
        size_t dataSize = 1;

        // Add the size of each one of the variables.
        for(size_t i = 0; i < variables.size(); i++)
            dataSize += variables[i]->GetSize();
        return dataSize;
    }

    void MessageBlock::Write(DataStream &out)
    {
        // Write the number of blocks byte.
    	boost::shared_ptr<const MessageBlockTemplate> tmpl = GetTemplate();
        if(tmpl->quantityType == MessageBlockTemplate::BQ_VARIABLE)
            out.WriteBig<u8> (subcount);

        // Write each one of the variables
        for(size_t i = 0; i < variables.size(); i++)
            variables[i]->Write(out);
    }

    void MessageBlock::Read(DataStream &in)
    {
        // Check if the block count is variable.
    	boost::shared_ptr<const MessageBlockTemplate> tmpl = GetTemplate();
        if(tmpl->quantityType == MessageBlockTemplate::BQ_VARIABLE)
        {
            // Read the number of sub blocks and create them.
            int numblocks;
            in.ReadBigTo<u8> (numblocks);
            SetNumberOfSubBlocks(numblocks);
        }

        // Read each one of the variables.
        for(size_t i = 0; i < variables.size(); i++)
            variables[i]->Read(in);
    }

    void MessageBlock::SetNumberOfSubBlocks(int count)
    {
        // Check if this call is valid.
    	boost::shared_ptr<const MessageBlockTemplate> tmpl = GetTemplate();
        assert(count <= 0xFF); // The numbers of blocks is a 8-bits numbers.
        assert(tmpl->quantityType == MessageBlockTemplate::BQ_VARIABLE);

        if(subcount == count)
            return;

        subcount = count;

        // Clear the variables.
        variables.clear();

        // Recreate them.
        //variables.reserve(tmpl.variables.size()*subcount);
        for(int i = 0; i < subcount; i++)
        {
            for(int j = 0; j < tmpl->variables.size(); j++)
                variables.push_back(boost::shared_ptr<MessageVariable> (new MessageVariable(j, this)));
        }
    }

    int MessageBlock::GetNumberOfSubBlocks() const
    {
        return subcount;
    }

    boost::shared_ptr<const MessageBlockTemplate> MessageBlock::GetTemplate() const
    {
        return parent->GetTemplate()->blocks[blockId];
    }

    MessageVariable &MessageBlock::GetVariable(int id, int subblock)
    {
        return *variables[id + subblock*GetTemplate()->variables.size()].get();
    }

    const MessageVariable &MessageBlock::GetVariable(int id, int subblock) const
    {
        return *variables[id + subblock*GetTemplate()->variables.size()].get();
    }

    MessageVariable &MessageBlock::GetVariable(const std::string &name, int subblock)
    {
        MessageBlockTemplate::VariablesCacheType::const_iterator f =
            GetTemplate()->variablesCache.find(name);
        assert(f != GetTemplate()->variablesCache.end());
        return *variables[f->second + subblock*GetTemplate()->variables.size()].get();
    }

    const MessageVariable &MessageBlock::GetVariable(const std::string &name, int subblock) const
    {
        MessageBlockTemplate::VariablesCacheType::const_iterator f =
            GetTemplate()->variablesCache.find(name);
        assert(f != GetTemplate()->variablesCache.end());
        return *variables[f->second + subblock*GetTemplate()->variables.size()].get();
    }

    // Message implementation.
    Message::Message(boost::shared_ptr<const MessageTemplate> tmpl)
     : messageTemplate(tmpl)
    {
        isReliable = false;

        // Create the blocks.
        size_t numblocks = messageTemplate->blocks.size();
        blocks.reserve(numblocks);
        for(int i = 0; i < numblocks; i++)
        {
            blocks.push_back(boost::shared_ptr<MessageBlock> (new MessageBlock(i, this)));
        }
    }

    Message::~Message()
    {
    }

    boost::shared_ptr<const MessageTemplate> Message::GetTemplate() const
    {
        return messageTemplate;
    }

    size_t Message::GetSize() const
    {
        // If the messsage size is not variable, return the cached size.
        if(!GetTemplate()->HasVariableSize())
            return GetTemplate()->GetMessageSize();

        // Add the size of each block.
        size_t messageSize = 0;
        for(size_t i = 0; i < blocks.size(); i++)
            messageSize += blocks[i]->GetSize();

        // Return the message size.
        return messageSize;
    }

    void Message::WriteMessage(DataStream &out)
    {
        // Write the message blocks.
        for(size_t i = 0; i < blocks.size(); i++)
            blocks[i]->Write(out);
    }

    void Message::ReadMessage(DataStream &in)
    {
        for(size_t i = 0; i < blocks.size(); i++)
            blocks[i]->Read(in);
    }

    MessageBlock &Message::GetBlock(int id)
    {
        return *blocks[id].get();
    }

    const MessageBlock &Message::GetBlock(int id) const
    {
        return *blocks[id].get();
    }

    MessageBlock &Message::GetBlock(const std::string &name)
    {
        MessageTemplate::BlocksCacheType::const_iterator f = messageTemplate->blocksCache.find(name);
        assert(f != messageTemplate->blocksCache.end());
        return *blocks[f->second].get();
    }

    const MessageBlock &Message::GetBlock(const std::string &name) const
    {
        MessageTemplate::BlocksCacheType::const_iterator f = messageTemplate->blocksCache.find(name);
        assert(f != messageTemplate->blocksCache.end());
        return *blocks[f->second].get();
    }

    boost::shared_ptr<Message> CreateMessage(const MessageTemplates &templates,
        MessageTemplate::Frequency freq, unsigned int id)
    {
        MessageTemplates::MessageId mid(freq, id);
        MessageTemplates::TemplatesIdsType::const_iterator it =
         templates.templatesIds.find(mid);
        if(it != templates.templatesIds.end())
        {
            //printf("CreateMessagefi: %s\n", templates.templates[it->second].name.c_str());
            return boost::shared_ptr<Message> (new Message(templates.templates[it->second]));
        }

        return boost::shared_ptr<Message> ();
    }

    boost::shared_ptr<Message> CreateMessage(const MessageTemplates &templates, const std::string &name)
    {
        //printf("CreateMessage: %s\n", name.c_str());
        MessageTemplates::TemplatesCacheType::const_iterator f = templates.templatesCache.find(name);
        if(f != templates.templatesCache.end())
        {
            return  boost::shared_ptr<Message> (new Message(templates.templates[f->second]));
        }

        printf("Fail\n");
        return boost::shared_ptr<Message> ();
    }
};
